﻿using System.Collections.Generic;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media;

namespace MicroMVVM.Helpers
{
    public class ExtendedVisualTreeHelper
    {
        /// <summary>
        /// Recursively fetches a parent element of the specified type.
        /// </summary>
        /// <typeparam name="T">Parent type</typeparam>
        /// <param name="element">This dependency object</param>
        /// <returns>DependencyObject</returns>
        public static T GetParent<T>(DependencyObject element)
            where T : DependencyObject
        {
            try
            {
                if (element == null) return default(T);

                var parent = VisualTreeHelper.GetParent(element);

                if (parent == null) return default(T);

                if (parent is T) return (T) parent;

                return GetParent<T>(parent);
            }
            catch
            {
                return default(T);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="element"></param>
        /// <returns></returns>
        public static IEnumerable<T> GetAncestors<T>(DependencyObject element)
            where T : DependencyObject
        {
            var parent = VisualTreeHelper.GetParent(element);

            while (parent != null)
            {
                var t = parent as T;

                if (t != null) yield return t;

                parent = VisualTreeHelper.GetParent(parent);
            }
        }

        /// <summary>
        /// Recursively fetches a child element of the specified type.
        /// </summary>
        /// <typeparam name="T">Child type</typeparam>
        /// <param name="element">This dependency object</param>
        /// <returns>DependencyObject</returns>
        public static T GetChild<T>(DependencyObject element)
            where T : DependencyObject
        {
            try
            {
                if (element == null) return default(T);

                var count = VisualTreeHelper.GetChildrenCount(element);

                for (var index = 0; index < count; index++)
                {
                    var child = VisualTreeHelper.GetChild(element, index);

                    if (child == null) return default(T);

                    if (child is T) return (T) child;

                    if (VisualTreeHelper.GetChildrenCount(child) > 0)
                        return GetChild<T>(child);
                }

                return default(T);
            }
            catch
            {
                return default(T);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="element"></param>
        /// <returns></returns>
        public static IEnumerable<T> GetDescendants<T>(DependencyObject element)
            where T : DependencyObject
        {
            if (element == null) yield break;

            for (var i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++)
            {
                var child = VisualTreeHelper.GetChild(element, i);

                if (child != null && child is T)
                    yield return (T) child;

                foreach (var nextChild in GetDescendants<T>(child))
                    yield return nextChild;
            }
        }
    }
}